using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using System;
using Autodesk.Revit.UI.Selection;
using System.Windows;
using System.Collections.Generic;
using System.Linq;

namespace CodRevit.ViewModels
{
    public partial class SimpleRoadViewModel : ObservableObject
    {
        private readonly UIApplication _uiapp;
        private readonly Document _doc;
        private readonly Window _window;
        private readonly ExternalEvent _externalEvent;
        private readonly SimpleRoadHandler _roadHandler;

        [ObservableProperty]
        private double _roadWidth = 6000;
        [ObservableProperty]
        private double _roadHeight = 300;
        [ObservableProperty]
        private string _status = "请点击开始拾取按钮选择道路中心线";

        public SimpleRoadViewModel(UIApplication uiapp, Window window, ExternalEvent externalEvent, SimpleRoadHandler roadHandler)
        {
            _uiapp = uiapp;
            _doc = uiapp.ActiveUIDocument.Document;
            _window = window;
            _externalEvent = externalEvent;
            _roadHandler = roadHandler;
        }

        [RelayCommand]
        private void PickCenterLine()
        {
            var uidoc = _uiapp.ActiveUIDocument;
            try
            {
                _window.Hide();
                var reference = uidoc.Selection.PickObject(
                    ObjectType.Element,
                    new ModelCurveSelectionFilter(),
                    "请选择道路中心线");

                CurveElement? centerLine = _doc.GetElement(reference.ElementId) as CurveElement;
                if (centerLine != null)
                {
                    _roadHandler.SetParameters(centerLine, RoadWidth, RoadHeight, message => Status = message);
                    _externalEvent.Raise();
                }
            }
            catch (Autodesk.Revit.Exceptions.OperationCanceledException)
            {
                Status = "操作已取消";
            }
            catch (Exception ex)
            {
                Status = $"错误：{ex.Message}";
            }
            finally
            {
                _window.Show();
                _window.Activate();
            }
        }
    }

    public class ModelCurveSelectionFilter : ISelectionFilter
    {
        public bool AllowElement(Element elem)
        {
            return elem is ModelCurve;
        }
        public bool AllowReference(Reference reference, XYZ position)
        {
            return false;
        }
    }

    public class SimpleRoadHandler : IExternalEventHandler
    {
        private readonly Document _doc;
        private CurveElement? _centerLine;
        private double _roadWidth;
        private double _roadHeight;
        private Action<string>? _statusCallback;

        public SimpleRoadHandler(Document doc)
        {
            _doc = doc;
        }

        public void SetParameters(CurveElement centerLine, double roadWidth, double roadHeight, Action<string> statusCallback)
        {
            _centerLine = centerLine;
            _roadWidth = roadWidth / 304.8;
            _roadHeight = roadHeight / 304.8;
            _statusCallback = statusCallback;
        }

        /// <summary>
        /// 执行创建简易道路的操作。该方法通过给定的中心线创建一个具有指定宽度和高度的道路模型。
        /// 道路创建过程包括:
        /// 1. 根据中心线生成道路轮廓点
        /// 2. 连接轮廓点形成闭合曲线
        /// 3. 通过轮廓拉伸生成3D实体
        /// 4. 创建Revit的DirectShape元素
        /// </summary>
        /// <param name="app">Revit应用程序接口，提供对Revit程序的访问</param>
        /// <remarks>
        /// 该方法使用以下成员变量:
        /// - _centerLine: 道路的中心线曲线元素
        /// - _roadWidth: 道路宽度(内部已转换为英尺单位)
        /// - _roadHeight: 道路高度(内部已转换为英尺单位)
        /// - _statusCallback: 用于报告进度和错误的回调函数
        /// </remarks>
        public void Execute(UIApplication app)
        {
            // 验证中心线是否已正确设置，如未设置则报错并退出
            if (_centerLine == null)
            {
                _statusCallback?.Invoke("错误：未设置道路中心线");
                return;
            }
            try
            {
                // 创建新事务以进行道路创建操作
                using (Transaction trans = new Transaction(_doc, "创建简易道路"))
                {
                    trans.Start();
                    // 获取中心线的几何曲线
                    Curve curve = _centerLine.GeometryCurve;
                    // 存储组成道路轮廓的所有点
                    List<XYZ> profilePoints = new List<XYZ>();
                    // 根据曲线特征计算最优分段数
                    int segments = GetOptimalSegments(curve);
                    _statusCallback?.Invoke($"正在创建道路，分段数：{segments}");

                    // 第一阶段：生成道路左侧轮廓点
                    // 从起点到终点，计算左侧偏移点
                    for (int i = 0; i <= segments; i++)
                    {
                        try
                        {
                            // 计算当前参数位置(0到1之间)
                            double param = i / (double)segments;
                            // 获取曲线上的点
                            XYZ point = curve.Evaluate(param, true);
                            // 计算该点的切线方向并归一化
                            XYZ tangent = curve.ComputeDerivatives(param, true).BasisX.Normalize();
                            // 获取竖直向上的方向
                            XYZ up = XYZ.BasisZ;
                            // 叉乘计算横向偏移方向（垂直于切线）
                            XYZ crossDirection = up.CrossProduct(tangent).Normalize();
                            // 计算左侧偏移点
                            XYZ leftPoint = point.Add(crossDirection.Multiply(-_roadWidth / 2));
                            profilePoints.Add(leftPoint);

                            // 在最后一个点处添加右侧点，用于连接右侧轮廓
                            if (i == segments)
                            {
                                XYZ rightPoint = point.Add(crossDirection.Multiply(_roadWidth / 2));
                                profilePoints.Add(rightPoint);
                            }
                        }
                        catch (Exception ex)
                        {
                            _statusCallback?.Invoke($"在处理点 {i} 时出错: {ex.Message}");
                            trans.RollBack();
                            return;
                        }
                    }

                    // 第二阶段：生成道路右侧轮廓点（反向）
                    // 从终点返回到起点，计算右侧偏移点
                    for (int i = segments - 1; i >= 0; i--)
                    {
                        try
                        {
                            double param = i / (double)segments;
                            XYZ point = curve.Evaluate(param, true);
                            XYZ tangent = curve.ComputeDerivatives(param, true).BasisX.Normalize();
                            XYZ up = XYZ.BasisZ;
                            XYZ crossDirection = up.CrossProduct(tangent).Normalize();
                            // 计算右侧偏移点
                            XYZ rightPoint = point.Add(crossDirection.Multiply(_roadWidth / 2));
                            profilePoints.Add(rightPoint);
                        }
                        catch (Exception ex)
                        {
                            _statusCallback?.Invoke($"在处理返回点 {i} 时出错: {ex.Message}");
                            trans.RollBack();
                            return;
                        }
                    }
                    // 第三阶段：创建闭合的道路轮廓
                    // 将所有点连接成线段，形成闭合的曲线环
                    CurveLoop roadProfile = new CurveLoop();
                    for (int i = 0; i < profilePoints.Count; i++)
                    {
                        XYZ p1 = profilePoints[i];
                        // 使用取模运算确保最后一个点与第一个点相连
                        XYZ p2 = profilePoints[(i + 1) % profilePoints.Count];
                        try
                        {
                            // 创建两点之间的直线段
                            Line line = Line.CreateBound(p1, p2);
                            roadProfile.Append(line);
                        }
                        catch (Exception ex)
                        {
                            _statusCallback?.Invoke($"创建线段失败: {ex.Message}");
                            trans.RollBack();
                            return;
                        }
                    }

                    // 第四阶段：创建3D几何体并完成道路创建
                    try
                    {
                        // 定义拉伸方向（向下）
                        XYZ extrusionDirection = new XYZ(0, 0, -1);
                        // 通过轮廓拉伸创建道路实体
                        Solid roadSolid = GeometryCreationUtilities.CreateExtrusionGeometry(
                            new CurveLoop[] { roadProfile },
                            extrusionDirection,
                            _roadHeight);

                        // 创建DirectShape元素用于在Revit中表示道路
                        DirectShape roadShape = DirectShape.CreateElement(_doc, new ElementId(BuiltInCategory.OST_GenericModel));
                        // 设置几何形状
                        roadShape.SetShape(new GeometryObject[] { roadSolid });
                        // 设置元素名称
                        roadShape.Name = "Simple Road";

                        // 设置默认材质


                        // 提交事务，完成道路创建
                        trans.Commit();
                        _statusCallback?.Invoke("道路创建成功！");
                    }
                    catch (Exception ex)
                    {
                        _statusCallback?.Invoke($"创建几何体失败: {ex.Message}");
                        trans.RollBack();
                    }
                }
            }
            catch (Exception ex)
            {
                _statusCallback?.Invoke($"整体执行失败: {ex.Message}");
            }
        }
        private int GetOptimalSegments(Curve curve)
        {
            // 增加基础分段数
            int baseSegments = 30;  // 从10增加到30
            // 如果是直线，使用较少的分段数
            if (curve is Line)
                return baseSegments / 2;  // 直线段使用15个分段
            try
            {
                // 获取曲线起点和终点参数
                double startParam = curve.GetEndParameter(0);
                double endParam = curve.GetEndParameter(1);
                // 计算曲线长度
                double length = curve.Length;
                // 增加采样点数量以获得更精确的曲率计算
                int samplePoints = 20;  // 从10增加到20
                double maxCurvature = 0;
                double totalCurvature = 0;
                XYZ lastTangent = null;
                for (int i = 0; i <= samplePoints; i++)
                {
                    double param = startParam + (endParam - startParam) * i / samplePoints;
                    XYZ currentTangent = curve.ComputeDerivatives(param, true).BasisX.Normalize();
                    if (lastTangent != null)
                    {
                        // 计算相邻切线之间的角度变化
                        double angleDiff = lastTangent.AngleTo(currentTangent);
                        totalCurvature += angleDiff;
                        maxCurvature = Math.Max(maxCurvature, angleDiff);
                    }
                    lastTangent = currentTangent;
                }
                double averageCurvature = totalCurvature / samplePoints;
                // 根据曲率和长度更激进地调整分段数
                int segments = baseSegments;
                // 根据最大曲率增加分段
                segments += (int)(maxCurvature * 200);  // 增加曲率影响
                // 根据平均曲率增加分段
                segments += (int)(averageCurvature * 100);
                // 根据长度调整，更细致的分段
                segments += (int)(length / 5);  // 每5英尺增加一个分段（之前是10英尺）
                // 调整最大和最小分段数的限制
                if (segments < baseSegments)
                    segments = baseSegments;
                if (segments > 300)  // 增加最大分段数限制，从100增加到300
                    segments = 300;
                _statusCallback?.Invoke($"曲线长度: {length:F2}英尺, 平均曲率: {averageCurvature:F3}, 最大曲率: {maxCurvature:F3}, 分段数: {segments}");
                return segments;
            }
            catch
            {
                _statusCallback?.Invoke($"曲率计算失败，使用基础分段数: {baseSegments}");
                return baseSegments;
            }
        }
        public string GetName() => "SimpleRoadHandler";
    }
}